package third.lib.wx.pay.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestClientException;
import third.lib.common.exception.ThirdException;
import third.lib.common.status.ThirdStatus;
import third.lib.utils.DateTimeUtils;
import third.lib.utils.StringUtils;
import third.lib.utils.XMLUtils;
import third.lib.wx.common.utils.WXUtils;
import third.lib.wx.pay.app.config.WxAppPayConfig;
import third.lib.wx.pay.app.model.WxAppPayOrder;
import third.lib.wx.pay.app.model.WxAppPayRet;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.Map.Entry;

//@Service
public class WxAppPay {
    private final Logger logger = LoggerFactory.getLogger(WxAppPay.class);
//    @Autowired
//    ThirdLogger thirdLogger;

    //    @Autowired
//    WxAppPayConfig config;
    WxAppPayConfig config;

    public WxAppPay(WxAppPayConfig config){
        this.config = config;
    }

    public WxAppPayOrder unifiedorder(String body, String outTradeNo, int total, String ip) throws ThirdException {
//        thirdLogger.info("微信统一下单: " + JSON.toJSONString(this.config));
        String nonceStr = WXUtils.getNonceStr();
        SortedMap<String, Object> parameters = new TreeMap();
        parameters.put("appid", this.config.getAppId());
        parameters.put("mch_id", this.config.getMchId());
        parameters.put("nonce_str", nonceStr);
        parameters.put("body", body);
        parameters.put("out_trade_no", outTradeNo);
        parameters.put("total_fee", total);
        parameters.put("spbill_create_ip", ip);
        parameters.put("notify_url", this.config.getNotifyUrl());
        parameters.put("trade_type", "APP");
        String sign = WXUtils.sign(parameters, this.config.getKey());
        String xmlStr = this.xmlOrder(nonceStr, body, outTradeNo, total, ip, sign);
        System.out.println(xmlStr);

        String response;
        try {
            response = (String) WXUtils.getRestTemplate().postForObject("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlStr, String.class, new Object[0]);
        } catch (RestClientException var16) {
            var16.printStackTrace();
            throw new ThirdException(ThirdStatus.NET);
        }

//        thirdLogger.info("微信统一支付返回: " + response);
        Map<String, Object> ret = XMLUtils.prase(response);
        if (ret == null) {
            logger.error(response);
            throw new ThirdException(ThirdStatus.WX);
        } else {
            ret = (HashMap) ret.get("xml");
            if (!ret.get("return_code").equals("SUCCESS")) {
                System.err.println(response);
                throw new ThirdException(ThirdStatus.WX);
            } else if (!ret.get("result_code").equals("SUCCESS")) {
                logger.error(response);
                throw new ThirdException(ThirdStatus.WX);
            } else {
                long seconds = DateTimeUtils.getSeconds();
                SortedMap<String, Object> appMap = new TreeMap();
                appMap.put("appid", this.config.getAppId());
                appMap.put("partnerid", this.config.getMchId());
                appMap.put("prepayid", ret.get("prepay_id"));
                appMap.put("package", "Sign=WXPay");
                appMap.put("noncestr", nonceStr);
                appMap.put("timestamp", seconds);

                try {
                    sign = WXUtils.sign(appMap, this.config.getKey());
                } catch (ThirdException var15) {
                    var15.printStackTrace();
                    throw var15;
                }

                WxAppPayOrder order = new WxAppPayOrder();
                order.setAppId(this.config.getAppId());
                order.setMchId(this.config.getMchId());
                order.setNonceStr(nonceStr);
                order.setTimeStamp(seconds);
                order.setPrepayId(ret.get("prepay_id").toString());
                order.setPackageValue("Sign=WXPay");
                order.setSign(sign);
                return order;
            }
        }
    }

    public Map<String, Object> getRetInfo(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try {
            InputStream inputStream = request.getInputStream();
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));

            String s;
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }

            in.close();
            inputStream.close();
            Map<String, Object> map = XMLUtils.prase(sb.toString());
            if(map != null) {
                map = (Map) map.get("xml");
            }
            return map;
        }catch (IOException ex){
            logger.error(ex.getMessage());
            return null;
        }
    }

    public WxAppPayRet verifySign(Map<String, Object> map) throws ThirdException {
        StringBuffer sb = new StringBuffer();
        try {
            SortedMap<String, Object> sortedMap = new TreeMap();
            Iterator itor = map.entrySet().iterator();

            while (itor.hasNext()) {
                Entry<String, Object> entry = (Entry) itor.next();
                sortedMap.put(entry.getKey(), entry.getValue());
            }

            String sign = WXUtils.sign(sortedMap, this.config.getKey());
            if (!sign.equalsIgnoreCase(map.get("sign").toString())) {
                throw new ThirdException(ThirdStatus.WX);
            } else {
                WxAppPayRet payRet = new WxAppPayRet();
                payRet.setResultCode(map.get("result_code").toString());
                if (payRet.getResultCode().equals("SUCCESS")) {
                    payRet.setReturnCode(StringUtils.praseToStr(map.get("return_code")));
                    payRet.setAppId(StringUtils.praseToStr(map.get("appid")));
                    payRet.setMchId(StringUtils.praseToStr(map.get("mch_id")));
                    payRet.setBankType(StringUtils.praseToStr(map.get("bank_type")));
                    payRet.setCashFee(Integer.valueOf(StringUtils.praseToStr(map.get("cash_fee"))));
                    payRet.setNonceStr(StringUtils.praseToStr(map.get("nonce_str")));
                    payRet.setOutTradeNo(StringUtils.praseToStr(map.get("out_trade_no")));
                    payRet.setTimeEnd(StringUtils.praseToStr(map.get("time_end")));
                    payRet.setTotalFee(Integer.valueOf(StringUtils.praseToStr(map.get("total_fee"))));
                    payRet.setTradeType(StringUtils.praseToStr(map.get("trade_type")));
                    payRet.setTransactionId(StringUtils.praseToStr(map.get("transaction_id")));
                    return payRet;
                } else {
                    this.logger.error(sb.toString());
                    throw new ThirdException(ThirdStatus.WX);
                }
            }
        } catch (ThirdException ex) {
            logger.error(ex.getMessage());
            throw new ThirdException(ThirdStatus.WX);
        }
    }

    public String Success() {
        return "<xml>\n  <return_code><![CDATA[SUCCESS]]></return_code>\n  <return_msg><![CDATA[OK]]></return_msg>\n</xml>";
    }

    public String Fail() {
        return "<xml>\n  <return_code><![CDATA[FAIL]]></return_code>\n  <return_msg><![CDATA[FAIL]]></return_msg>\n</xml>";
    }

    private String xmlOrder(String nonceStr, String body, String outTradeOut, int total, String ip, String sign) {
        StringBuffer bf = new StringBuffer();
        bf.append("<xml>");
        bf.append("<appid><![CDATA[");
        bf.append(this.config.getAppId());
        bf.append("]]></appid>");
        bf.append("<body><![CDATA[");
        bf.append(body);
        bf.append("]]></body>");
        bf.append("<mch_id><![CDATA[");
        bf.append(this.config.getMchId());
        bf.append("]]></mch_id>");
        bf.append("<nonce_str><![CDATA[");
        bf.append(nonceStr);
        bf.append("]]></nonce_str>");
        bf.append("<notify_url><![CDATA[");
        bf.append(this.config.getNotifyUrl());
        bf.append("]]></notify_url>");
        bf.append("<out_trade_no><![CDATA[");
        bf.append(outTradeOut);
        bf.append("]]></out_trade_no>");
        bf.append("<spbill_create_ip><![CDATA[");
        bf.append(ip);
        bf.append("]]></spbill_create_ip>");
        bf.append("<total_fee><![CDATA[");
        bf.append(total);
        bf.append("]]></total_fee>");
        bf.append("<trade_type><![CDATA[");
        bf.append("APP");
        bf.append("]]></trade_type>");
        bf.append("<sign><![CDATA[");
        bf.append(sign);
        bf.append("]]></sign>");
        bf.append("</xml>");
        return bf.toString();
    }
}

